// *************************************************************************************************
//
// MK3D Engine
// --------------------------------------
// Copyright (C) 2007-2011 Zeb (mailto: zebbey@gmail.com)
//
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//
// *************************************************************************************************

#ifndef __H_MK_ENGINE__
#define __H_MK_ENGINE__

namespace MK3DE
{
	enum RENDER_DEVICE_TYPE
	{
		RDT_DIRECT3D9
	};

	class CRenderWindow;
	class CLog;
	class CRenderDevice;
	class CResourceManager;
	class CSceneManager;
	class CPainter;
	class CTimer;
	class CFileSystem;
	class CProfiler;
	class CCamera;
	class CParticlePool;
	class CParticleRenderer;
	class CPostProcessorManager;
	class CTexture2D;

	class MK3DE_API CEngine
	{
	public:
		CEngine();
		~CEngine();

	public:
		//! Create engine.
		/** 
		\param renderDeviceType : render device type.
		\param mainWndHandle : main window handle.
		\return : If the method succeeds, return TRUE or return FALSE. 
		*/
		BOOL Create(RENDER_DEVICE_TYPE renderDeviceType, void* mainWndHandle);

		//! Create a render window from the specified window handle.
		/**
		Post process only apply to the first render window.

		\param wndHandle : window handle.
		\return : a pointer of the new render window.
		*/
		CRenderWindow* CreateRenderWindow(void* wndHandle);

		//! Get render window pointer by window handle.
		/**
		\param wndHandle : window handle.
		\return : a pointer of the specified window.
		*/
		CRenderWindow* GetRenderWindow(void* wndHandle);

		//! Destroy render window
		/**
		\param wndHandle : window handle.
		\return : If the method succeeds, return TRUE or return FALSE. 
		*/
		BOOL DestroyRenderWindow(void* wndHandle);

		//! Render all render window.
		void Render();

		//! Update all render window.
		void Update();

		//! Get some interface of sub-system.
		CLog* GetLog() { return _engineLog; }
		CRenderDevice* GetRenderDevice() { return _renderDevice; }
		CResourceManager* GetResourceManager() { return _resourceManager; }
		CSceneManager* GetSceneManager() { return _sceneManager; }
		CPainter* GetPainter() { return _painter; }
		CTimer* GetTimer() { return _timer; }
		CFileSystem* GetFileSystem() { return _fileSystem; }
		CPostProcessorManager* GetPostProcessorManager() { return _postProcessorManager; }

#if MK_PROFILER_ENABLE
		CProfiler* GetProfiler() { return _profiler; }
#endif

		//! Notify the size of a window is changed.
		/**
		\param wndHandle : window handle.
		\return : None.
		*/
		void OnRenderWindowResize(void* wndHandle);

		//! Set and get current camera.
		CCamera* GetCurrentCamera() { return _currentCamera; }
		void SetCurrentCamera(CCamera* camera);

		//! Set and get current render window.
		CRenderWindow* GetCurrentRenderWindow() { return _currentRenderWindow; }
		void SetCurrentRenderWindow(CRenderWindow* renderWindow);

		//! Set and get current shadow map.
		CTexture2D* GetCurrentShadowMap() { return _currentShadowMap; }
		void SetCurrentShadowMap(CTexture2D* shadowMap) { _currentShadowMap = shadowMap; }

		//! Set and get current reflection map.
		CTexture2D* GetCurrentReflectionMap() { return _currentReflectionMap; }
		void SetCurrentReflectionMap(CTexture2D* reflectionMap) { _currentReflectionMap = reflectionMap; }

		//! Set and get current refraction map.
		CTexture2D* GetCurrentRefractionMap() const { return _currentRefractionMap; }
		void SetCurrentRefractionMap(CTexture2D* refractionMap) { _currentRefractionMap = refractionMap; }

	public:
		/** internal method */
		CParticlePool* _GetParticlePool() { return _particlePool; }
		CParticleRenderer* _GetParticleRenderer() { return _particleRenderer; }

	private:
		BOOL __GetRenderWindow(void* wndHandle, std::vector<CRenderWindow*>::iterator& i);
		void __RecalculateCameraAspectRatio();

	private:
		RENDER_DEVICE_TYPE _renderDeviceType;
		CLog* _engineLog;
		CRenderDevice* _renderDevice;
		CResourceManager* _resourceManager;
		CSceneManager* _sceneManager;
		CPainter* _painter;
		CTimer* _timer;
		CFileSystem* _fileSystem;
		CPostProcessorManager* _postProcessorManager;

#if MK_PROFILER_ENABLE
		CProfiler* _profiler;
#endif

		CParticlePool* _particlePool;
		CParticleRenderer* _particleRenderer;

		CCamera* _currentCamera;
		CRenderWindow* _currentRenderWindow;

		std::vector<CRenderWindow*> _vecRenderWindow;

		CTexture2D* _currentShadowMap;
		CTexture2D* _currentReflectionMap;
		CTexture2D* _currentRefractionMap;
	};

	extern "C" MK3DE_API BOOL CreateEngine(RENDER_DEVICE_TYPE renderDeviceType, void* mainWndHandle);
	extern "C" MK3DE_API CEngine* GetEngine();
	extern "C" MK3DE_API void DestroyEngine();
};

#endif // __H_MK_ENGINE__